# 日志的记录与异常重试的装饰器
"""
程序运行自封装库
作者:xunter
版本:V1.0.0
日期:2024-11-20
"""
import os
import time
from typing import Any
from retrying import retry


def work_logger(path:str = 'logs',is_retry:bool=True) -> Any:
    """
    第一层装饰器函数  得到传入到参数
    爬虫工作日志装饰器
    :param is_retry: 是否需要重试操作
    :param path: 日志文件存放目录
    :return:
    """
    # 判断是否存在日志文件夹地址,不存在就创建
    if not os.path.isdir(path):
        os.mkdir(path)

    def get_old_func(old_func):
        """
        得到原有函数
        :param old_func:原有函数
        :return:
        """
        def new_func(*args, **kwargs):
            """
            升级后的函数 并且得到原有的参数(*args, **kwargs)
            :param args:
            :param kwargs:
            :return:
            """
            # 2024-11-20 19:14:46 :<function test at 0x0000023813AAE050>((1, 2),{})
            with open(rf'{path}/info.txt','a',encoding='utf-8') as f:
                f.write('%s :%s(%s,%s)\n' % (
                    time.strftime('%Y-%m-%d %H:%M:%S'),
                    old_func,
                    args,
                    kwargs
                ))

            try:
                res = old_func(*args, **kwargs)  #在升级后的函数中使用原本的函数传入原本的参数  执行原本的功能
            except TimeoutError as e:
                #单独处理超时异常
                if is_retry:
                    @retry(stop_max_attempt_number=3, wait_random_min=1000, wait_random_max=3000)
                    def time_retry():
                        """
                        定义time_retry函数 在time_retry函数中调用old_func原本函数
                        在time_retry函数中加了一个retry重试装饰器  会对函数里面的内容进行检查，如果发送异常，则重新调用
                        如果是超时异常就调用time_retry函数在其中调用old_func返回old_func函数的返回值
                        如果还是报错就调用@retry装饰器进行重试  重试3次后任然不行就抛出异常  如果不想让报错影响程序运行可以选择不使用重试方法is_retry=False
                        :return:
                        """
                        # 加入进度条提示
                        # tqdm.write('正在重试。。。')
                        with open(rf'{path}/retry.txt', 'a', encoding='utf-8') as f:
                            f.write('%s :%s(%s,%s) retry info:[%s]\n' % (
                                time.strftime('%Y-%m-%d %H:%M:%S'),
                                old_func,
                                args,
                                kwargs,
                                e
                            ))
                        return old_func(*args, **kwargs)  # 执行原本函数
                    return time_retry()

                else:
                    # 不需要重试就跳过，并且开始尝试下一个数据的获取  跳过的文件单独保存
                    with open(rf'{path}/pass.txt', 'w', encoding='utf-8') as f:
                        f.write('%s|%s' % (args,kwargs))

            except Exception as e:
                # tqdm.write('异常跳过。。。')
                with open(rf'{path}/error.txt', 'a', encoding='utf-8') as f:
                    f.write('%s :%s(%s,%s) error info:[%s]\n' % (
                        time.strftime('%Y-%m-%d %H:%M:%S'),
                        old_func,
                        args,
                        kwargs,
                        e
                    ))
            else:
                with open(rf'{path}/success.txt', 'a', encoding='utf-8') as f:
                    f.write('%s :%s(%s,%s) res:[%s] \n' % (
                        time.strftime('%Y-%m-%d %H:%M:%S'),
                        old_func,
                        args,
                        kwargs,
                        res
                    ))
                # 如果成功的话需要返回原本函数的返回值
                return res

        return new_func

    return get_old_func
